#include<stdio.h>
#include<pthread.h>
#include<iostream>
#include<unistd.h>
#include<queue>

//线程安全队列

#define MAX_QUEUE 5

template<class T>
class BlockQueue{
  private:
    std::queue<T> _q;
    int _capacity;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond_pro;
    pthread_cond_t _cond_con;
public:
    BlockQueue(int capacity = MAX_QUEUE):_capacity(capacity){
       //构造函数初始化
       pthread_mutex_init(&_mutex,NULL);
       pthread_cond_init(&_cond_pro,NULL);
       pthread_cond_init(&_cond_con,NULL);
    }
    ~BlockQueue(){
       pthread_mutex_destroy(&_mutex);
       pthread_cond_destroy(&_cond_pro); 
       pthread_cond_destroy(&_cond_con); 
    }
   
    bool Push(T& data){
      pthread_mutex_lock(&_mutex);  //加锁
      while(_capacity==_q.size()){
         //队列已满
         pthread_cond_wait(&_cond_pro,&_mutex);   //阻塞生产者
      }
      _q.push(data); //数据入队
      pthread_cond_signal(&_cond_con);  //唤醒消费者
      pthread_mutex_unlock(&_mutex);  //解锁
    }
  
    bool Pop(T* data)
    {
      pthread_mutex_lock(&_mutex);
      while(_q.empty()){
         pthread_cond_wait(&_cond_con,&_mutex);  //队列为空，阻塞消费者
      } 
      *data=_q.front();
      _q.pop();
      pthread_cond_signal(&_cond_pro);   //出队数据之后，唤醒生产者
      pthread_mutex_unlock(&_mutex);
    }
};

//任务队列-------包含要处理的数据和处理方法
template<class T>
class ThreadTask{
public:
  //using Handler = std::function<void(T)>;      //等价于  typedef void(*Handler)(T)  定义函数类型
  typedef void(*Handler)(T);
  ThreadTask() {}
  ThreadTask(const T &data,Handler handler):_data(data),_handler(handler){
     //构造方法
     
  }
  
  void Start(){
     return _handler(_data);      //调用指定方法处理指定数据
  }
private:
  T _data; //要处理的数据
  Handler _handler;   //处理方法
};

//线程池
template<class T>
class ThreadPool{
private:
  int _thread_max;      //线程池中最大线程数量
  BlockQueue<ThreadTask<T>> _queue;       //线程安全等待队列---其中存储的是一个结构体类型数据（要处理数据+处理函数）
  std::vector<pthread_t> _tid;    //保存所有线程的tid
private:
  //循环从任务队列中获取任务，调用任务的Start接口进行任务处理
  static void* thread_entry(void* arg){          //线程入口函数要求只有一个 void* 类型参数，因此需要使用 static 定义静态成员函数，否则还会存在一个隐藏的 this 指针参数
    while(1){
      ThreadPool* pool=(ThreadPool*)arg;     //类型强转
      ThreadTask<T> task; //获取一个任务
      pool->_queue.Pop(&task); 
      task.Start();
    }
    return NULL;
  }
public:
  //创建指定数量的线程
  ThreadPool(int thread_max,int queue_max):_thread_max(thread_max),_queue(queue_max){  
      int ret;
      pthread_t tid;
      for(int i=0;i<thread_max;++i){
         ret=pthread_create(&tid,NULL,thread_entry,this);
         if(ret!=0){
           perror("pthread_create error!\n");
           exit(-1);
         }
      }
  }

  //任务的入队操作
  bool Push(ThreadTask<T> &task){
     _queue.Push(task);
     return true;
  }
};

void print_test(int data)
{
  printf("%p thread run data: %d\n",pthread_self(),data);
  sleep((data%3)+1);
}

int main()
{  
  ThreadPool<int> pool(5,10);                //5个线程，10个等待队列
  for(int i=0;i<10;++i){
    ThreadTask<int> task(i,print_test);      //入队十个任务
    pool.Push(task);
  }
  while(1) sleep(10);
  return 0;
}




